var EnableSync = 1;

var TodoStorage = function (items, categories) {
    var t = this;

    this.items = [];

    //c3 start
    this.categories = [];
    //c3 end

    this.syncTimer = null;
    this.syncInterval = 30000;
    this.syncErrorsCount = 0;

    var currentRequest = null;

    /*this.init = function (items) {
     if (typeof items != "undefined") {
     this.items = items;
     }
     }*/
    this.init = function (items, categories) {
        if (typeof items != "undefined") {
            this.items = items;
        }

        if (typeof categories != "undefined") {
            this.categories = categories;
        }
    }
    // items start
    /*
     * @param name
     */
    this.addItem = function (name, category) {
        name = name.replace(/(<([^>]+)>)/ig, "");
        var items = this.items;

        //c3 start
        var category_name = '';
        if (category != 'undefined')
            category_name = category;
        //c3 end

        var isExists = false;
        $(items).each(function (key, val) {
            if (val.name == name) {
                isExists = true;
                return false;
            }
        });

        if (isExists) {
            return false;
        }

        items.push({
            id: 'new',
            name: name.replace(/(<([^>]+)>)/ig, ""),
            completed: false,
            deleted: false,
            category: category_name,
            category_id: null,
            position: 0

        });

        this.setItems(items);

        this.afterItemAdded();

        return true;
    }

    /**
     *
     */
    this.afterItemAdded = function () {
    }

    /**
     * Update items in storage
     * @param items
     * @param noSync
     */
    this.setItems = function (items, noSync) {
        if (items) {
            this.items = items;

            updateStorage(items);
        }

        if (typeof noSync == "undefined") {
            this.sync();
        }

        this.afterSetItems();
    }

    this.afterSetItems = function () {
    }

    /**
     *
     * @param id
     * @param action
     * @param value
     */
    this.updateItem = function (id, action, value) {
        if (!id || !action) {
            return false;
        }

        var items = this.items;

        var res = [];
        $(items).map(function (key, val) {
            if (key == id) {
                switch (action) {
                    case 'delete':
                        val.deleted = true;
                        break;
                    case 'complete':
                        val.completed = true;
                        break;
                    case 'edit':
                        val.name = value.replace(/(<([^>]+)>)/ig, "");
                        break;
                }
            }

            res.push(val);
        });

        this.setItems(res);

        this.afterItemUpdated();

        return true;
    }

    /**
     *
     */
    this.afterItemUpdated = function () {
    }

    /**
     *
     * @param itemId
     */
    this.remItem = function (itemId) {
        if (itemId != 'number') {
            return;
        }

        var items = this.items;

        if (items[itemId] != undefined) {
            delete items[itemId];

            this.setItems(items);
        }
    }

    /**
     *
     * @param name
     */
    this.addCategory = function (name) {
        name = name.replace(/(<([^>]+)>)/ig, "");
        var categories = this.categories;

        var isExists = false;
        $(categories).each(function (key, val) {
            if (val.name == name) {
                isExists = true;
                return false;
            }
        });

        if (isExists) {
            return false;
        }

        categories.push({
            id: 'new',
            name: name.replace(/(<([^>]+)>)/ig, ""),
            deleted: false,
            position: 0
        });

        this.setCategories(categories);

        this.afterCategoryAdded();

        return true;
    }

    /**
     *
     */
    this.afterCategoryAdded = function () {
    }

    /**
     * Update categories in storage
     * @param categories
     * @param noSync
     */
    this.setCategories = function (categories, noSync) {
        // alert('setCategories'); alert(categories);
        if (categories) {
            this.categories = categories;
            // alert(this.categories);
            updateCategoriesStorage(categories);
        }

        if (typeof noSync == "undefined") {
            this.sync();
        }

        this.afterSetItems();
    }

    this.afterSetItems = function () {
    }

    /**
     *
     * @param id
     * @param props
     */
    this.updateCategory = function (id, action, value) {
        if (!id || !action) {
            return false;
        }

        var categories = this.categories;

        var res = [];
        $(categories).map(function (key, val) {

            if (key == id) {
                switch (action) {
                    case 'delete':
                        val.deleted = true;
                        break;

                    case 'edit':
                        val.name = value.replace(/(<([^>]+)>)/ig, "");
                        break;
                }
            }

            res.push(val);
        });

        this.setCategories(res);

        this.afterCategoryUpdated();

        return true;
    }

    /**
     *
     */
    this.afterCategoryUpdated = function () {
    }

    /**
     *
     * @param categoryId
     */
    this.remCategory = function (categoryId) {
        if (categoryId != 'number') {
            return;
        }

        var categories = this.categories;

        if (categories[categoryId] != undefined) {
            delete categories[categoryId];

            this.setCategories(categories);
        }
    }
    // categories end

    this.sync = function (dontStopRequest) {

        if (!EnableSync)
            return;


        var self = this,
            items = self.items,
        //c3 start
            categories = self.categories;
        // c3 end


        clearTimeout(self.syncTimer);

        if (items.length == 0) {
            items = 'no items';
        }
        // c3 start
        if (categories.length == 0) {
            categories = 'no categories';
        }
        // c3 end

        if (currentRequest != null && typeof dontStopRequest == "undefined") {
            currentRequest.abort();

            currentRequest = null;
        }

        var dataChanged = function (data) {
            var currentItems = self.items;
            var currentCategories = self.categories;

            if (data.items != currentItems || data.categories != currentCategories) {
                return true;
            }

            return false;
        }


        /* var html = $.ajax({
         type: "POST",
         url: "/api/todosync",
         data: {items: items, categories: categories},
         dataType: "html",
         async: false
         }).responseText;

         alert(html);*/
        //dump(categories[0]);
        currentRequest = $.ajax({
            url: "/api/todosync",
            type: 'POST',
            data: {items: items, categories: categories},
            dataType: 'json',
            timeout: 60000,
            success: function (data, textStatus, jqXHR) {
                if (!data.data || !data.errors || data.errors && data.errors.items > 0) {
                    self.onSyncError(data, textStatus, jqXHR);
                    return;
                }

                if (dataChanged(data.data)) {
                    self.setItems(data.data.items, true);
                    self.setCategories(data.data.categories, true);
                }

                currentRequest = null;
                self.syncErrorsCount = 0;

                self.afterSync();
            },
            error: function (data, textStatus, jqXHR) {
                currentRequest = null;

                ++self.syncErrorsCount;

                self.onSyncError(data, textStatus, jqXHR);
            }
        });
    }

    this.afterSync = function () {
        var self = this;

        clearTimeout(self.syncTimer);

        self.syncTimer = setTimeout(function () {
            self.sync();
        }, self.syncInterval);

        self.onSyncSuccessful();
    }

    this.onSyncSuccessful = function () {

    }

    this.onSyncError = function (data, textStatus, jqXHR) {
        var self = this;

        clearTimeout(self.syncTimer);

        self.syncTimer = setTimeout(function () {
            self.sync();
        }, 10000);
    }

    this.filterItems = function(filter) {
        var items = t.items,
            result = [];

        var categoryId = 0,
            type = '';

        if(typeof filter != "object") {
            return result;
        }

        var categoryNumerical = (typeof filter.categoryId != "undefined" && parseInt(filter.categoryId) > 0);
        var categoryIsNull = (typeof filter.categoryId == "object" && filter.categoryId === null);

        var filterByCategory = (categoryNumerical || categoryIsNull);
        var filterByType = (typeof filter.type == "string" && $.inArray(filter.type, ['due','date', 'other']) >= 0);

        if(filterByCategory) {
            categoryId = filter.categoryId;
        }

        if(filterByType) {
            type = filter.type;
        }

        $.each(items, function(key, item) {
            if(filterByCategory && categoryId != item.category_id) {
                return;
            }

            if(filterByType) {
                switch(type) {
                    case 'due':
                        if(!item.expired) {
                            return;
                        }
                        break;
                    case 'date':
                        if(!item.deadline) {
                            return;
                        }
                        break;
                    case 'other':
                        if(item.expired || item.deadline) {
                            return;
                        }
                        break;
                }
            }

            result.push(item);
        });

        return result;
    }

    this.init(items, categories);
}

function isLocalStorageAvailable() {
    try {
        return 'localStorage' in window && window['localStorage'] !== null;
    } catch (e) {
        return false;
    }
}

function updateStorage(items) {
    if (!isLocalStorageAvailable()) return;

    if (typeof items != "object" || !items) {
        return;
    }

    localStorage.setItem(getStorageKey('todoItems'), JSON.stringify(items));

    return true;
}

function updateCategoriesStorage(items) {
    if (!isLocalStorageAvailable()) return;

    if (typeof items != "object" || !items) {
        return;
    }

    localStorage.setItem(getStorageKey('todoCategories'), JSON.stringify(items));

    return true;
}

function getStorageKey(key) {


    if (typeof storageKey == 'string') {
        key += storageKey;
    }

    return key;
}

function getFromStorage() {
    if (!isLocalStorageAvailable()) return;

    var res = localStorage.getItem(getStorageKey('todoItems'));

    if (res) {
        return JSON.parse(res);
    } else {
        return false;
    }

    return true;
}

function getCategoriesFromStorage() {
    if (!isLocalStorageAvailable()) return;

    var res = localStorage.getItem(getStorageKey('todoCategories'));
    //alert('cfs');alert(res);
    if (res) {
        return JSON.parse(res);
    } else {
        return false;
    }

    return true;
}

function dump(obj) {
    var out = "";
    if (obj && typeof(obj) == "object") {
        for (var i in obj) {
            out += i + ": " + obj[i] + "\n";
        }
    } else {
        out = obj;
    }
    alert(out);
}